[ Nuxt.js 2.x 系列文章 ] VueX Store 搭配 vuex-persistedstate 狀態保存工具


版本:nuxt 2.15.8

前情提要一下,在 Vue 的專案下,常會需要做父子元件或是頁面之間的溝通傳值,如果說只是單層(ex:父元件 → 子元件、子元件 → 父元件、頁面 → 頁面),我們可以很簡單的使用 propsemitevent bus 即可,但在大型專案,共用資料就不是如此單純,可能會有元件內含元件、多層級的溝通,如果只用上述方法,對於開發及除錯都不便利,如下圖範例,元件 1-1元件 2-1 的溝通相對複雜。

為了處理高難度溝通,VueX 狀態管理工具就誕生了,那麼在 Nuxt 專案下又該怎麼使用呢?

首先先安裝 VueX 套件 npm i vuex@3.6.2

💡 Nuxt v2.x 必須搭配 VueX v3.x

接著在專案最外層新增 store 資料夾,並在裡面建立 .js 檔,範例使用 userInfo.js

export const state = () => {};
export const getters = {};
export const mutations = {};
export const actions = {};

Nuxt 專案會自動創建實例 new Vuex.Store(),將 store 檔案包裝進模組內,像這樣:

new Vuex.Store({
    modules: {
        userInfo: {
            namespaced: true,
            state: () => {},
            getters: {},
            mutations: {},
            actions: {}
        }
    }
});

VueX 基本架構:

  • state:用以儲存狀態,功能同 .vue 檔內的 data,因此會使用方法來包裝,並 return 內容
  • getters:功能同 computed,用以計算 state 內的狀態,不能直接改變 state
  • mutations:用來更改 state,不能使用非同步語法
  • actions:非同步語法只能寫在 actions,不能直接改變 state,需透過 mutations 改變 state

接著來替 store 加入一些內容吧

export const state = () => ({
    count: 0,
    products: [
        {
            name: 'food',
            onSale: false
        },
        {
      name: 'drink',
            onSale: true
        }
    ]
});
export const getters = {
    onSaleProducts(state) {
        return state.products.filter(item => item.onSale);
    }
};
export const mutations = {
    increment(state, number) {
    state.count += number;
  }
};
export const actions = {
    incrementAsync({ commit }, number) {
    setTimeout(() => {
      commit('increment', number);
    }, 1000);
  }
};

如果要在頁面使用 store 的內容,有以下兩種方式:

透過 this.$store 操作

VueX 將 store 注入到 Vue 實例,因此我們透過 $store 就可以取得相關資料及方法,

使用方式如下(範例頁面 pages/about.vue):

export default {
    name: 'About',
  computed: {
        count() { // state
            return this.$store.state.userInfo.count;
        }
        onSaleProducts() { // getters
            return this.$store.getters['userInfo/onSaleProducts'];
        }
    },
    methods: {
        increment(number) { // mutations
            this.$store.commit('userInfo/increment', number);
        },
        incrementAsync(number) { // actions
            this.$store.dispatch('userInfo/incrementAsync', number);
        }
    }
}

但是每一筆資料或是方法,都透過 this.$store 取得,程式碼冗長,如果今天我們有三個 store 儲存庫,易讀性又更低了,難道沒有簡單的使用方式嗎?

透過輔助函式

VueX 提供一系列輔助函式(mapState, mapGetters, mapMutations, mapActions),可以幫助我們更簡易的取得 store 內容,首先必須從 VueX 引入輔助函式,接著來改寫 about.vue 頁面

import { mapState, mapGetters, mapMutations, mapActions } from 'vuex';

export default {
    name: 'About',
  computed: {
        ...mapState('userInfo', [ 'count' ]),
        ...mapGetters('userInfo', [ 'onSaleProducts' ])
    },
    methods: {
        ...mapMutations('userInfo', [ 'increment' ]),
        ...mapActions('userInfo', [ 'incrementAsync' ])
    }
}

透過輔助函式,減少許多程式碼,閱讀起來也輕鬆許多。


VueX 相當方便,但還是存在一個問題,就是當頁面重新整理的時候,會回復到初始狀態。

某些情境下,我們需要保留更新後的資料,例如登入後儲存使用者資訊到 store,重整頁面後資料被清空,使用者必須重新登入。為了解決這個問題,我們可以將資料儲存於 localStorage,待畫面重整後再將資料取回放入 store,或者是使用套件 vuex-persistedstate

💡 2022.02.04 vuex-persistedstate **套件已不繼續維護更新

接下來說明如何 Nuxt 專案如何搭配 vuex-persistedstate,存放在 localStorage 的內容,可以輕易地被讀取,因此我們需要將內容加密(搭配套件 secure-ls

首先安裝套件:npm i vuex-persistedstate

接著安裝加密套件:npm i secure-ls

於 plugins 增加檔案,範例使用 persistedstate.js

import createPersistedState from 'vuex-persistedstate';
import SecureLS from 'secure-ls';

const ls = new SecureLS({
    encodingType: 'aes', // 加密方式,預設 base64
    isCompression: false, // 是否壓縮數據
    encryptionSecret: process.env.APP_KEY // 加密 key
});

export default ({ store, isHMR }) => {
    if (isHMR) { // 避免在熱更新的時候重複觸發(npm run dev)
        return;
    }
    window.onNuxtReady(() => {
        createPersistedState({
            key: 'test', // 自訂 localStorage key
            storage: {
                getItem: key => ls.get(key),
                setItem: (key, value) => ls.set(key, value),
                removeItem: key => ls.remove(key)
            }
        })(store);
    });
};

接著配置到 nuxt.config.js 內

export default {
    plugins: [
        { src: '@/plugins/persistedstate', ssr: false }
    ]
}

這樣一來即使畫面重整,store 也可以順利保存資料,在 localStorage 查看 test 內容也確實被加密了!


參考文章:

https://medium.com/itsems-frontend/vue-vuex1-state-mutations-364163b3acac

https://chiafangsung.medium.com/使用-vuex-persistedstate-維持-vuex-狀態-f0d7c522c73a

#Nuxt #nuxt.js #Vue #Vue.js #ssr #vuex #store







你可能感興趣的文章

【Vue 學習筆記】Pinia 製作購物車

【Vue 學習筆記】Pinia 製作購物車

失敗的 git 操作

失敗的 git 操作

The introduction and difference between class component and function component in React

The introduction and difference between class component and function component in React






留言討論